<?php

namespace slinks\extensions\action\core;

use slinks\extensions\action\core\ISlinksActionManager;
use slinks\extensions\action\configuration\IConfiguration;
use slinks\extensions\action\configuration\Configuration;
use slinks\extensions\action\core\IActionResolver;
use slinks\core\HttpFoundation\IRequest;
use slinks\extensions\action\routing\Matcher\Exception\NotFoundException;
use slinks\extensions\action\exception\NotFoundHttpException;
use slinks\extensions\action\exception\MethodNotAllowedHttpException;
use slinks\extensions\action\routing\Matcher\Exception\MethodNotAllowedException;
use slinks\extensions\action\routing\RouterInterface;
use slinks\core\DependencyInjection\ContainerInterface;

/**
 * Responsible for handling requests and returning results.
 * 
 * @author Navid Mitchell
 *
 */
class SlinksActionManager implements IFrontController {
    /* @var $configuration Configuration */

    private $container;
    private $configuration;
    private $router;
    
    function __construct(ContainerInterface $container,
                         IConfiguration $configuration,
                         RouterInterface $router) {
        $this->container = $container;
        $this->configuration = $configuration;
        $this->router = $router;
    }

    /**
     * Handle the given request.
     * @param $request IRequest
     */
    public function handle(IRequest $request) {
        // first intialize request (route)
        $this->initializeSession($request);

        $this->initializeIRequestAttributes($request);
        
        /* @var $actionMapping IActionMapping */
        $actionMapping = $this->configuration->findActionMapping($request->attributes()->get('_route'));

        $actionContext = new ActionContext($actionMapping, $request);
        
        $actionInvocation = $this->configuration->findActionInvocation($actionContext);

        // Invoke the interceptor chain.
        // This is where all of the real work is done
        // See the individual interceptors for their contribution
        $actionInvocation->invoke();

        return $actionInvocation->getReturnValue();
    }
    
    protected function initializeSession(IRequest $request){

        // inject the session object if none is present
        if (null === $request->getSession() && $this->container->has('session')) {
            $request->setSession($this->container->get('session'));
        }

        // starts the session if a session cookie already exists in the request...
        if ($request->hasSession()) {
            $request->getSession()->start();
        }
    }

    protected function initializeIRequestAttributes(IRequest $request){

        // set the context even if the parsing does not need to be done
        // to have correct link generation
        $this->router->setContext(array(
            'base_url'  => $request->getBaseUrl(),
            'method'    => $request->getMethod(),
            'host'      => $request->getHost(),
            'port'      => $request->getPort(),
            'is_secure' => $request->isSecure(),
        ));

        // add attributes based on the path info (routing)
        try {
            $pathInfo = $request->getPathInfo();
            $parameters = $this->router->match($request->getPathInfo());

           /* if (null !== $this->logger) {
                $this->logger->info(sprintf('Matched route "%s" (parameters: %s)', $parameters['_route'], $this->parametersToString($parameters)));
            }*/

            $request->attributes()->add($parameters);

            if ($locale = $request->attributes()->get('_locale')) {
                $request->getSession()->setLocale($locale);
            }
        } catch (NotFoundException $e) {
            $message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo());
           /* if (null !== $this->logger) {
                $this->logger->err($message);
            }*/
            throw new NotFoundHttpException($message, $e);
        } catch (MethodNotAllowedException $e) {
            $message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getPathInfo(), strtoupper(implode(', ', $e->getAllowedMethods())));
           /* if (null !== $this->logger) {
                $this->logger->err($message);
            }*/
            throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e);
        }
    }
    

}
